#ifndef sntText_H
#define sntText_H

#include "snt.h"
#include "svl_TText.h"
#include "svl_TStackPtrFix.h"

namespace snt { namespace text {

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// ';' - Semicolon
// ':' - DDot
// '{' - LBrace
// '}' - RBrace
// '[' - LBracket
// ']' - RBracket
// '(' - LPrnt
// ')' - RPrnt
// '+' - Plus
// '-' - Minus
// '*' - Asterisk
// '\' - LSlash
// '/' - RSlash
// '^' - Cover

////////////////////////////////////////////////////////////////////////////////
struct TContext;
struct TText;
struct TEndOfText;
struct TSearchEndOfLine;

////////////////////////////////////////////////////////////////////////////////

struct TDebug
{
  TDebug() { objectsCount++;}
 ~TDebug() { objectsCount--;}
  //
  static void Check();

private:

private:
  struct TCheck
  {
   ~TCheck() { TDebug::Check();}
  };
  static int objectsCount;
  static TCheck check;
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TErrors : public TDebug
{
  struct TError : public svl::TArray_Object,public TDebug
  {
    svl::TString Message;
    int          Line,Col;
    //
    TError() { Line = Col = -1;}
    void operator = (TError &V) { Message = V.Message; Line = V.Line; V.Col = Col;}
  };
  //
  void Clear() { a.Clear(); }
  void Add(TText &Text,char *Message);
  void Add(int NLine,int NCol,char *Message);
  //
  void AddToLastMessage(char *Message);
  //
  int Count()        { return a.Numb();}
  TError &Get(int N) { return *static_cast<TError*>(a.Get(N));}
  //
  svl::TString GetAsString(svl::TString Offs = "");
  svl::TString GetInfo();
  
private:
  svl::TArray a;
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TText
{
  TText() { nLine = nCol = 0;}
  //
  void operator = (svl::TMem &V) { CopyFrom(V);}
  //
  void CopyFrom(svl::TMem  &V) { text.MakeLines(V); nLine = nCol = 0;}
  void CopyFrom(svl::TText &V) { text.CopyFrom (V); nLine = nCol = 0;}
  //
  bool LoadFromFile(svl::TString FileName);
  //
  int GetNLine() { return nLine;}
  int GetNCol()  { return nCol;}
  void SetNLineNCol(int NLine,int NCol) { nLine = NLine; nCol = NCol;}
  //
  char GetSym ();
  bool GetLine(svl::TString &Line,int &NCol);
  bool GetLine(svl::TString &Line)  { int N; return GetLine(Line,N);}
  svl::TString *GetLinePtr(int &OutNCol);
  //
  bool SetNextPos(int Delta);
  bool SetNextLine();
  //
  bool IsAlpha(char Sym);
  bool IsDigit(char Sym);
  //
  int           CountLines()   { return text.CountLines();}
  svl::TString &GetLine(int N) { return text.GetLine(N);}
  //
  svl::TString GetInfo() { return text.GetInfo(); }

private:
  int nLine,nCol;
  svl::TText text;
  friend TErrors;
  friend TEndOfText;
  friend TSearchEndOfLine;
};

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

struct TRuleComment : public snt::TRule
{
  TRuleComment(TContext &Context);
  //
  virtual bool Execute();
  
private:
  TContext &context;
  snt::TAlter AThis,ALine,ABlockBegin,ABlockEnd;
  friend TContext;
};

///////////////////////////////////////////////////////////////////////////////

struct TConcreteContext : public TDebug
{
  TText   Text;
  //TErrors Errors;
};

///////////////////////////////////////////////////////////////////////////////

struct TContext : public TDebug
{
  TText   &Text()   { return GetPop()->Text;}
  TErrors &Errors() { return errors;}//concreteContext->Errors;}
  svl::TBTableString Keywords;
  //
  TContext() : ruleComment(*this) { enRuleComment = true; stack.Push(&defConcreteContext);}
  //
  void Push(TConcreteContext *V) { stack.Push(V);}
  TConcreteContext *Pop()        { return stack.Pop();}
  TConcreteContext *GetPop()     { return stack.GetPop();}
  //
  void PassGarbage();
  svl::TString GetErrorsInfo();

private:
TErrors errors;
  void PassSpaceAndEOL();
  TRuleComment ruleComment;
  bool enRuleComment;
  TConcreteContext defConcreteContext;
  svl::TStackPtrFix<TConcreteContext*,20> stack;
  friend TRuleComment;
};

///////////////////////////////////////////////////////////////////////////////

struct TToken : public snt::TToken
{
  virtual void DoNextPos() {}
  virtual void DoError_InPreview() {}
};

///////////////////////////////////////////////////////////////////////////////

struct TNextContext : public TToken
{
  struct TFuncDoEntryParams
  {
    TNextContext &NextContext;
    TConcreteContext *OutConcreteContext;
    svl::TString OutError;
    //
    TFuncDoEntryParams(TNextContext &NextContext_) : NextContext(NextContext_) { OutConcreteContext = NULL;}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncDoEntryParams &Params)> TFuncDoEntry;

  template<class PObj,class PFunc> TToken &New(PObj pObj,PFunc pFunc) {
    TNextContext *P = new TNextContext(context); 
      P->funcDoEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }

public:
  TNextContext(TContext &V);

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoNextPos();
  virtual void DoError();
  virtual void DoError_InPreview();
  
private:
  TContext &context;
  svl::TString error;
  TFuncDoEntry funcDoEntry;
  svl_Except;
};

///////////////////////////////////////////////////////////////////////////////

struct TPrevContext : public TToken
{
  TToken &New() {
    TPrevContext *P = new TPrevContext(context); 
      P->isNew = true; 
    return *P;
  }

public:
  TPrevContext(TContext &V);

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoNextPos();
  virtual void DoError();
  virtual void DoError_InPreview();
  
private:
  TContext &context;
  svl::TString error;
  svl_Except;
};

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

struct TPreview : public TToken
{
public:
  TPreview(TContext &V);
  //
  TToken &New(TToken &T0);
  TToken &New(TToken &T0,TToken &T1);
  TToken &New(TToken &T0,TToken &T1,TToken &T2);
  //
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private:
  TContext &context;
  snt::TObjectArray a;
  TToken *tError;
  svl_Except;
};


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TEndOfText : public TToken
{
  TEndOfText(TContext &V);
  //
  TToken &New();

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private:
  TContext &context;
};

////////////////////////////////////////////////////////////////////////////////

struct TSearchEndOfLine : public TToken
{
  TSearchEndOfLine(TContext &V);
  //
  TToken &New();

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private:
  TContext &context;
};

///////////////////////////////////////////////////////////////////////////////

struct TEnumSet : public TToken
{
  struct TFuncGetEnumSetParams
  {
    svl::TEnumSet *OutEnumSet;
    //
    TFuncGetEnumSetParams() { OutEnumSet = NULL;}
  };
  typedef fastdelegate::FastDelegate<void(TFuncGetEnumSetParams &Params)> TFuncGetEnumSet;

  template<class PObj,class PFunc> TEnumSet &New(PObj pObj,PFunc pFunc) {
    TEnumSet *P = new TEnumSet(context); 
      P->isNew = true; 
      P->funcGetEnumSet.bind(pObj,pFunc);
    return *P;
  }
  
  struct TFuncDoEntryParams
  {
    TEnumSet &Token;
    svl::TString OutError;
    //
    TFuncDoEntryParams(TEnumSet &Token_) : Token(Token_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncDoEntryParams &Params)> TFuncDoEntry;

  template<class PObj,class PFunc> TEnumSet &SetDoEntry(PObj pObj,PFunc pFunc) {
    if (!isNew) {
      Except("SetDoEntry[!isNew]");
    }
    funcDoEntry.bind(pObj,pFunc);
    return *this;
  }

  TEnumSet(TContext &V);
  //
  svl::TEnumSet *GetEnumSet() { return enumSet;}
  int GetNValue() { return nValue;}   

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  //
  virtual void DoNextPos();
  virtual void DoError_InPreview();
  
private:
  bool CheckSequence();
  //
  TContext &context;
  svl::TString error;
  svl::TEnumSet *enumSet;
  int nValue;
  TFuncGetEnumSet funcGetEnumSet;
  TFuncDoEntry funcDoEntry;
  svl_Except;
};

///////////////////////////////////////////////////////////////////////////////

struct TSequence : public TToken
{
  struct TFuncClosureDoEntryParams
  {
    TSequence   &Sequence;
    svl::TString OutError;
    //
    TFuncClosureDoEntryParams(TSequence &Sequence_) : Sequence(Sequence_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncClosureDoEntryParams &Params)> TFuncClosureDoEntry;

  template<class PObj,class PFunc> TToken &NewClosure(svl::TString Sequence,PObj pObj,PFunc pFunc) {
    if (!Sequence.Len()) {
      Except("New[!Sequence.Len()]");
    }
    TSequence *P = new TSequence(context); 
      P->s = Sequence; 
      P->funcClosureDoEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }


  struct TFuncDoEntryParams
  {
    svl::TPointer *PObject;
    TSequence     &Sequence;
    svl::TString   OutError;
    //
    TFuncDoEntryParams(TSequence &Sequence_) : Sequence(Sequence_) {}
  };
  typedef void (/*__closure*/ *TFuncDoEntry)(TFuncDoEntryParams &Params);

  struct TEvents
  {
    virtual bool TEvents_EnEntry(TSequence &Sequence,svl::TString &OutError) { return true; }
    virtual bool TEvents_DoEntry(TSequence &Sequence,svl::TString &OutError) { return true; }
  };
  TSequence(TContext &V);
  //
  TToken &New(svl::TString Sequence);
  TToken &New(svl::TString Sequence,svl::TVariant &OutSequence);
  TToken &New(svl::TString Sequence,TEvents &Events);
  TToken &New(svl::TString Sequence,svl::TPointer *PObject,TFuncDoEntry FuncDoEntry);
  //
  svl::TString GetSequence() { return s; }

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  //
  virtual void DoNextPos();
  virtual void DoError_InPreview();
  
private:
  bool CheckSequence();
  //
  TContext &context;
  svl::TString s;
  bool evError;
  svl::TString error;
  TEvents *events;
  svl::TVariant *outSequence;
  
  svl::TPointer *pObject;
  TFuncDoEntry funcDoEntry;
  TFuncClosureDoEntry funcClosureDoEntry;
  svl_Except;
};

///////////////////////////////////////////////////////////////////////////////

struct TSearchSequence : public TToken
{
  struct TEvents
  {
    virtual bool TEvents_EnEntry(TSearchSequence &SearchSequence,svl::TString &OutError) { return true; }
    virtual bool TEvents_DoEntry(TSearchSequence &SearchSequence,svl::TString &OutError) { return true; }
  };
  TSearchSequence(TContext &Context);
  //
  TToken &New(svl::TString Sequence);
  TToken &New(svl::TString Sequence,TEvents &Events);
  //
  svl::TString GetSequence() { return s; }

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private:
  bool CheckSequence();
  //
  TContext &context;
  int begNCol,endNCol;
  svl::TString s;
  bool evError;
  svl::TString error;
  TEvents *events;
  svl_Except;
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TNumber : public TToken
{
  struct TFuncClosureDoEntryParams
  {
    TNumber     &Number;
    svl::TString OutError;
    //
    TFuncClosureDoEntryParams(TNumber &Number_) : Number(Number_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncClosureDoEntryParams &Params)> TFuncClosureDoEntry;

  template<class PObj,class PFunc> TToken &NewClosure(PObj pObj,PFunc pFunc) {
    TNumber *P = new TNumber(context); 
      P->funcClosureDoEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }


  struct TFuncDoEntryParams
  {
    svl::TPointer *PObject;
    TNumber       &Number;
    svl::TString   OutError;
    //
    TFuncDoEntryParams(TNumber &Number_) : Number(Number_) {}
  };
  typedef void (/*__closure*/ *TFuncDoEntry)(TFuncDoEntryParams &Params);

  struct TEvents
  {
    virtual bool TEvents_EnEntry(TNumber &Number,svl::TString &OutError) { return true; }
    virtual bool TEvents_DoEntry(TNumber &Number,svl::TString &OutError) { return true; }
  };
  TNumber(TContext &Context);
  //
  TToken &New(svl::TVariant &Value);
  TToken &New(svl::TVariant &Value,TEvents &Events);
  TToken &New(svl::TPointer *PObject,TFuncDoEntry FuncDoEntry);
  //
  svl::TVariant &GetValue() { if (!value) { Except("GetValue[!value]"); } return *value; }

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  bool MakeValue(int &Value,int &Len);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private: svl_Except;
  TContext  &context;
  svl::TVariant *value,defValue;
  int nLine,nCol;
  svl::TString error;
  TEvents     *events;
  
  svl::TPointer *pObject;
  TFuncDoEntry funcDoEntry;
  TFuncClosureDoEntry funcClosureDoEntry;
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TIdent : public TToken
{
  struct TFuncClosureDoEntryParams
  {
    TIdent      &Ident;
    svl::TString OutError;
    //
    TFuncClosureDoEntryParams(TIdent &Ident_) : Ident(Ident_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncClosureDoEntryParams &Params)> TFuncClosureDoEntry;

  template<class PObj,class PFunc> TIdent &NewClosure(PObj pObj,PFunc pFunc) {
    TIdent *P = new TIdent(context); 
      P->funcClosureDoEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }

  struct TFuncClosureEnEntryParams
  {
    TIdent      &Ident;
    svl::TString OutError;
    //
    TFuncClosureEnEntryParams(TIdent &Ident_) : Ident(Ident_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncClosureEnEntryParams &Params)> TFuncClosureEnEntry;

  template<class PObj,class PFunc> TIdent &NewClosureEnEntry(PObj pObj,PFunc pFunc) {
    TIdent *P = new TIdent(context); 
      P->funcClosureEnEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }

  template<class PObj,class PFunc> TIdent &SetEnEntry(PObj pObj,PFunc pFunc) {
    if (!isNew) {
      Except("SetEnEntry[!isNew]");
    }
    funcClosureEnEntry.bind(pObj,pFunc);
    return *this;
  }

/**********
  template<class PObj,class PFuncEn,class PFuncDo> TToken &NewClosureEnDoEntry(PObj pObj,PFuncEn pFuncEn,PFuncDo pFuncDo) {
    TIdent *P = new TIdent(context); 
      P->funcClosureEnEntry.bind(pObj,pFuncEn);
      P->funcClosureDoEntry.bind(pObj,pFuncDo);
      P->isNew = true; 
    return *P;
  }
*************/

  struct TFuncDoEntryParams
  {
    svl::TPointer *PObject;
    TIdent        &Ident;
    svl::TString   OutError;
    //
    TFuncDoEntryParams(TIdent &Ident_) : Ident(Ident_) {}
  };
  typedef void (/*__closure*/ *TFuncDoEntry)(TFuncDoEntryParams &Params);


  struct TEvents
  {
    virtual bool TEvents_EnEntry(TIdent &Ident,svl::TString &OutError) { return true; }
    virtual bool TEvents_DoEntry(TIdent &Ident,svl::TString &OutError) { return true; }
  };

  //
  TIdent(TContext &Context);
  //
  TToken &New();
  TToken &New(svl::TVariant &Value);
  TToken &New(svl::TVariant &Value,TEvents &Events);
  TToken &New(TEvents &Events);
  TToken &New(svl::TPointer *PObject,TFuncDoEntry FuncDoEntry);
  //
  svl::TVariant &GetValue() { if (!value) { Except("GetValue[!value]"); } return *value; }
  //
  int GetNLine() { return nLine;}
  int GetNCol()  { return nCol;}

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  bool MakeValue(svl::TString &Value,int &Len);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  //
  virtual void DoNextPos();
  virtual void DoError_InPreview();

private:
  TContext  &context;
  svl::TVariant *value,defValue;
  int nLine,nCol;
  svl::TString error;
  TEvents *events;
  
  svl::TPointer *pObject;
  TFuncDoEntry funcDoEntry;
  TFuncClosureDoEntry funcClosureDoEntry;
  TFuncClosureEnEntry funcClosureEnEntry;
  svl_Except;
};

////////////////////////////////////////////////////////////////////////////////

struct TKeyword : public TToken
{
  struct TFuncClosureDoEntryParams
  {
    TKeyword    &Keyword;
    svl::TString OutError;
    //
    TFuncClosureDoEntryParams(TKeyword &Keyword_) : Keyword(Keyword_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncClosureDoEntryParams &Params)> TFuncClosureDoEntry;

  template<class PObj,class PFunc> TToken &NewClosure(svl::TString Keyword,PObj pObj,PFunc pFunc) {
    TKeyword *P = new TKeyword(context); 
      P->keyword = Keyword; 
      P->funcClosureDoEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }



  struct TEvents
  {
    virtual bool TEvents_EnEntry(TKeyword &Keyword,svl::TString &OutError) { return true; }
    virtual bool TEvents_DoEntry(TKeyword &Keyword,svl::TString &OutError) { return true; }
  };
  TKeyword(TContext &V);
  //
  TToken &New(svl::TString Keyword);
  TToken &New(svl::TString Keyword,svl::TVariant &OutKeyword);
  TToken &New(svl::TString Keyword,TEvents &Events);
  //
  svl::TString GetKeyword() { return keyword; }
  //
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  //
  bool MakeValue(svl::TString &Value,int &Len);

public:
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private: svl_Except;
  TContext &context;
  svl::TString keyword;
  svl::TString error;
  TEvents *events;
  svl::TVariant *outKeyword;

  TFuncClosureDoEntry funcClosureDoEntry;
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TString : public TToken
{
  struct TFuncClosureDoEntryParams
  {
    TString      &String;
    svl::TString OutError;
    //
    TFuncClosureDoEntryParams(TString &String_) : String(String_) {}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncClosureDoEntryParams &Params)> TFuncClosureDoEntry;

  template<class PObj,class PFunc> TToken &NewClosure(PObj pObj,PFunc pFunc) {
    TString *P = new TString(context); 
      P->funcClosureDoEntry.bind(pObj,pFunc);
      P->isNew = true; 
    return *P;
  }


  struct TFuncDoEntryParams
  {
    svl::TPointer *PObject;
    TString       &String;
    svl::TString   OutError;
    //
    TFuncDoEntryParams(TString &String_) : String(String_) {}
  };
  typedef void (/*__closure*/ *TFuncDoEntry)(TFuncDoEntryParams &Params);
  //
  TString(TContext &V);
  //
  svl::TVariant &GetValue() { return *value; }
  //
  TToken &New();
  TToken &New(svl::TVariant &Value);
  TToken &New(svl::TPointer *PObject,TFuncDoEntry FuncDoEntry);

protected:
  virtual svl::TString GetInfo(EOutGraphInfo OutGraphInfo);
  bool MakeValue(svl::TString &Value,int &Len);
  //
  virtual bool EnEntry();
  virtual bool DoEntry();
  virtual void DoError();
  
private: svl_Except;
  TContext &context;
  svl::TVariant *value,defValue;
  
  svl::TString error;
  svl::TPointer *pObject;
  TFuncDoEntry funcDoEntry;
  TFuncClosureDoEntry funcClosureDoEntry;
};

////////////////////////////////////////////////////////////////////////////////
}}

#endif

